from django.contrib.auth import logout, login, authenticate
from django.contrib.auth.models import User
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from spargameproject.decorators import csrf_www, csrf_www_transaction
from spargameproject.settings import OS_ROOT, MEDIA_ROOT
from spargameproject.spargame.game.engine.game_engine import GameEngine
from spargameproject.spargame.models import Player, Game, GamePlayer, Play, PlayMetaData, GameMetaData, GamePlayerMetaData
import Image
import math
import os
import traceback
import urllib

game_engine = GameEngine()

def getContext(req, player):
  context = {"images": getAvatarFiles()}
  context['requests'] = getFriendRequests(player)
  return context

@csrf_www(check_auth=True)
def showAvailableGames(req, player=None):
  context = getContext(req, player)
  context['profile'] = player
  context['friends'] = getRelationships(player)
  pending_requests = getPendingRequests(player)
  context['games'] = getAvailableGames(player, context['friends'],
                                       [request['player_id'] for request in context['requests']],
                                       pending_requests)
  context['pages'] = range(1, 1 + int(math.ceil(float(len(context['games'])) / 7)))
  context['forwarding_page'] = 'index.html'
  return context

def getAvailableGames(player, friends, requested, pending_requests):
  result = []
  games = Game.objects.filter(completion_timestamp=None).order_by('-creation_timestamp')
  for game in games:
    game_dict = {'id': game.id, 'current_player': False, 'name': game.name }
    game_dict['created_by'] = game.creator_player.name
    game_dict['created_by_id'] = game.creator_player.id
    if str(game_dict['created_by_id']) in friends:
      game_dict['friend_status'] = 'friends'
    if game_dict['created_by_id'] in requested:
      game_dict['friend_status'] = 'received_request'
    if game_dict['created_by_id'] in pending_requests:
      game_dict['friend_status'] = 'pending_request'
    game_dict['creation_time'] = game.creation_timestamp
    game_dict['players'] = []
    for game_player in game.getActiveGamePlayers():
      player_in_game = game_player.player or Player(name='Bot')
      player_dict = {'status': 'offline', 'score': 0}
      if player_in_game.id == player.id:
        game_dict['current_player'] = True
        player_dict['current_player'] = True
      player_dict['name'] = player_in_game.name
      player_dict['id'] = player_in_game.id
      player_status = player_in_game.getMetadata('status')
      if player_status == 'connected':
        player_dict['status'] = 'online'
      game_player_status = game_player.getMetadata('status')
      if game_player_status == 'connected':
        player_dict['status'] = 'playing'
      player_score = game_player.gameplayermetadata_set.filter(data_key='score')
      if player_score:
        player_dict['score'] = player_score[0]

      if str(player_dict['id']) in friends:
        player_dict['friend_status'] = 'friends'
      if player_dict['id'] in requested:
        player_dict['friend_status'] = 'received_request'
      if player_dict['id'] in pending_requests:
        player_dict['friend_status'] = 'pending_request'
      game_dict['players'].append(player_dict)
    result.append(game_dict)

  return result

def getFriendRequests(player):
  result = []
  request_metadatas = PlayMetaData.objects.filter(play__valid=True, play__play_type='add-friend',
                                            data_key='to', data_value=player.id)
  for request_metadata in request_metadatas:
    request = request_metadata.play
    request_sender = request.getMetadata('from')
    player = Player.objects.get(id=request_sender.data_value)
    result.append({'player_name': player.name, 'player_id': player.id, 'play_id': request.id})
  return result

def getPendingRequests(player):
  result = []
  request_metadatas = PlayMetaData.objects.filter(play__valid=True, play__play_type='add-friend',
                                            data_key='from', data_value=player.id)
  for request_metadata in request_metadatas:
    request = request_metadata.play
    request_receiver = request.playmetadata_set.get(data_key='to')
    if request_receiver.data_value.isdigit():
      player = Player.objects.get(id=request_receiver.data_value)
      result.append(player.id)
  return result

def getRelationships(player):
  result = []
  relationships = PlayMetaData.objects.filter(play__valid=True, play__play_type='create-relationship',
                                              data_value=player.id)
  for relationship in relationships:
    if relationship.data_key == 'from':
      to_rel = relationship.play.playmetadata_set.get(data_key='to')
      result.append(to_rel.data_value);
    if relationship.data_key == 'to':
      from_rel = relationship.play.playmetadata_set.get(data_key='from')
      result.append(from_rel.data_value);
  return result

#@csrf_www_auth_transaction
#def createFriendRequest(req, player=None):
#  user_name = req.POST['user_name']
#  user_avatar = req.POST['user_avatar']
#  player.name = user_name
#  player.setMetadata('avatar_img', user_avatar)
#  player.save()
#  return {}

#@csrf_protect
#@www_required
#def respondToFriendRequest():
#  player = None
#  try:
#    player = req.user.get_profile()
#  except Exception:
#    return render_to_response('unregistered.html', {}, context_instance=RequestContext(req))
#  user_name = req.POST['user_name']
#  user_avatar = req.POST['user_avatar']
#  player.name = user_name
#  player.setMetadata('avatar_img', user_avatar)
#  player.save()
#  return HttpResponse("ok")
#
@csrf_www(check_auth=False)
def openid_login(req, player=None):
  return {'next': '/processlogin/', 'forwarding_page': 'openid/login.html'}

@csrf_www(check_auth=False)
def openid_logout(req, player=None):
  logout(req)
  return {'forwarding_page': 'unregistered.html'}

@csrf_www(check_auth=False)
def processlogin(req, player=None):
  try:
    req.user.get_profile()
  except Exception:
    user_profile = Player()
    user_profile.user = req.user
    user_profile.name = req.user.first_name
    user_profile.save()
  return {'response_redirect': '/'}

@csrf_www_transaction(check_auth=True)
def updateProfile(req, player=None):
  user_name = req.POST['user_name']
  user_avatar = req.POST['user_avatar']
  player.name = user_name
  player.setMetadata('avatar_img', user_avatar)
  player.save()
  return {}

def joinGameBody(req, game_id, player):
  if not game_id:
    game_id = req.GET['game_id']
  game = Game.objects.get(pk=game_id)
  GamePlayer.objects.get_or_create(game=game, player=player)
  if game.getMetadata('in_progress'):
    observers = game.getMetadata('observers') or set()
    observers.add(player.id)
    game.setMetadata('observers', observers)
  return game_id

@csrf_www_transaction(check_auth=True)
def joinGame(req, player=None):
  game_id = joinGameBody(req, None, player)
  return {'response_redirect': '/playGame?game_id=%s' % game_id}

@csrf_www_transaction(check_auth=True)
def quitGame(req, player=None):
  game_id = req.POST['game_id']
  game_player = player.gameplayer_set.get(game=game_id)
  game_player.setMetadata('forfeit', True)
  return {}

@csrf_www(check_auth=True)
def playGame(req, player=None):
  context = getContext(req, player)
  context['profile'] = player
  game_id = req.GET['game_id']
  game = Game.objects.get(pk=game_id)
  try:
    game_player = player.gameplayer_set.get(game=game)
  except:
    context['errors'] = ['You are not a member of this game']
    context['forwarding_page'] = 'index.html'
  else:
    if game.isActivePlayer(game_player):
      context['game'] = game
      context['game_player'] = game_player
      context['forwarding_page'] = 'game.html'
    else:
      context['errors'] = ['You are not a member of this game']
  return context

@csrf_www_transaction(check_auth=True)
def createGame(req, player=None):
  game_name = req.POST.get('game_name')
  metadata_array = req.POST.getlist('metadata[]')
  game = Game.objects.create(creator_player=player)

  metadata = dict([item.split(':') for item in metadata_array])
  for key, value in metadata.iteritems():
    game_metadata = GameMetaData.objects.create(game=game, data_key=key, data_value=value)
    game.gamemetadata_set.add(game_metadata)

  game.name = game_name or game.id
  game_engine.initGame(game)
  game.save()
  joinGameBody(req, game.id, player)
  return {'forwarding_page': 'index.html'}

@csrf_www_transaction(ajax=True, check_auth=True)
def makePlay(request, player=None):
  game_id = request.POST.get('game_id')
  play_type = request.POST.get('play_type')
  metadata_array = request.POST.getlist('metadata[]')
  response = game_engine.makePlay(metadata_array, game_id, player, play_type)
  return response

@csrf_exempt
def updateConnectedStatus(request):
  try:
    print 'getting my updates yo!'
    player_id = request.POST.get('player_id')
    if not player_id:
      return
    player = Player.objects.get(pk=player_id)
    game_id = request.POST.get('game_id')
    status = request.POST.get('status')
    print 'player %s in game %s is now %s' % (player_id, game_id, status)

    if game_id != '0':
      game = Game.objects.get(pk=game_id)
      game_player = GamePlayer.objects.get(game=game, player=player)
      game_player.setMetadata('status', status)
    else:
      player.setMetadata('status', status)

    return HttpResponse("ok")
  except Exception, e:
    traceback.print_exc()
    return HttpResponse(e)

@csrf_www(check_auth=True, ajax=True)
def isPlayerNameUnique(req, player=None):
  name = req.POST.get('name')
  unique = False
  if  not req.user.is_anonymous() and name == player.name:
    unique = True
  else:
    split_name = name.split('_')
    if (len(split_name) == 2 and split_name[0] == 'player' and split_name[1].isdigit()) or '|' in name:
      unique = False
    else:
      players_with_name = Player.objects.filter(name=name).count()
      unique = players_with_name == 0
  return {'unique': unique}

@csrf_www_transaction(check_auth=True, ajax=True)
def cancelPlay(req, player=None):
  play_id = req.POST.get('play_id')
  play = Play.objects.get(id=play_id)
  play.valid = False
  play.save()
  return {}

@csrf_www_transaction(ajax=True)
def createPlayer(req, player=None):
  username = req.POST.get('username')
  password = req.POST.get('password')
  user = User.objects.create_user(username, '', password)
  user.save()
  player = Player.objects.create(user=user, name=username)
  player.save()
  user = authenticate(username=username, password=password)
  login(req, user)
  return {'response_redirect': '/'}

@csrf_www
def signIn(req, player=None):
  username = req.POST.get('username')
  password = req.POST.get('password')
  user = authenticate(username=username, password=password)
  if user is not None:
    login(req, user)
    return {'response_redirect': '/'}
  else:
    return {'forwarding_page': 'unregistered.html', 'retry': True}

def getAvatarFiles():
  images = []
  os_root = OS_ROOT
  image_path = '%s/media/images/avatar-thumbnails' % os_root
  image_url = '/site_media/images/avatar-thumbnails'
  os.chdir(image_path)
  for file in os.listdir("."):
    if '.jpg' in file:
      images.append('%s/%s' % (image_url, file))
  return list(chunks(images, 12))

def chunks(l, n):
    """ Yield successive n-sized chunks from l.
    """
    for i in xrange(0, len(l), n):
        yield l[i:i + n]

@csrf_www(check_auth=True, ajax=True)
def uploadImage(req, player=None):
  file = req.FILES['image_file']
  path = '%s/images/uploads/%s/%s' % (MEDIA_ROOT, player.id, urllib.quote(file.name))
  dir = os.path.dirname(path)
  if not os.path.exists(dir):
    os.makedirs(dir)
  destination = open(path, 'wb+')
  for chunk in file.chunks():
    destination.write(chunk)
  destination.close()
  response = {}
  response['Cache-Control'] = "no-cache"
  response['Pragma'] = "no-cache"
  return response

@csrf_www_transaction(ajax=True, check_auth=True)
def setAvatarFromUpload(req, player=None):
  file_name = req.POST.get('file_name')
  path = '%s/images/uploads/%s/%s' % (MEDIA_ROOT, player.id, urllib.quote(file_name))
  infile = Image.open(path)
  actual_width, actual_height = infile.size

  x1, y1, x2, y2, scaled_w, scaled_h = (
      float(req.POST.get('x1')), float(req.POST.get('y1')), float(req.POST.get('x2')) ,
      float(req.POST.get('y2')), float(req.POST.get('image_width')), float(req.POST.get('image_height')))

  x_factor = scaled_w / actual_width
  y_factor = scaled_h / actual_height

  left, upper, right, lower = int(round(x1 / x_factor)), int(round(y1 / y_factor)), int(round(x2 / x_factor)), int(round(y2 / y_factor))
  box = (left, upper, right, lower)
  region = infile.crop(box)

  outfile = '%s/images/uploads/%s/custom_avatar.png' % (MEDIA_ROOT, player.id)

  out_image = Image.new('RGBA', (int(math.fabs(right - left)), int(math.fabs(lower - upper))))

  out_image.paste(region)
  out_image.thumbnail((300, 300), Image.ANTIALIAS)
  out_image.save(outfile, 'PNG')
  outfile_url = '/site_media/images/uploads/%s/custom_avatar.png' % (player.id)
  player.setMetadata('avatar_img', outfile_url)
  return {}

@csrf_www(check_auth=True, ajax=True)
def getNameAndAvatar(req, player=None):
  return {'avatar': player.getAvatar(), 'name': player.name}


@csrf_www(check_auth=False)
def valentimes(req, player=None):
  name = req.POST.get('name')
  food = req.POST.get('food')
  date = req.POST.get('date')

  if not name and not food and not date:
    return {'forwarding_page': 'quiz.html', 'errors': False}

  correct = 'nii' in name or 'Nii' in name
  correct = correct and 'sushi' in food or 'Sushi' in food or 'halal' in food or 'Halal' in food
  correct = correct and 'Village Underground' in date or 'village underground' in date

  if correct:
    return {'forwarding_page': 'valentimes.html', 'errors': False}
  else:
    return {'forwarding_page': 'quiz.html', 'errors': True}

@csrf_www(check_auth=True, ajax=True)
def getBots(request, player=None):
  game_id = request.POST.get('game_id')
  bot_metadata = GamePlayerMetaData.objects.filter(
      game_player__game=game_id, data_key='is_bot', data_value=True)
  bots = [metadata.game_player.player.id for metadata in bot_metadata]
  return {'bots': bots}
